package com.wiseasy.ecrutils;

import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidParameterException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android_serialport_api.SerialPort;

public class SerialPortUtils {

    private static final String TAG = SerialPortUtils.class.getSimpleName();
    private SerialPort mSerialPort;
    private FileOutputStream serialPortOutputStream;
    private FileInputStream serialPortInputStream;
    private ExecutorService singleThreadExecutor;
    public boolean waitPortData;

    private SerialPortUtils() {
        if (singleThreadExecutor == null) {
            singleThreadExecutor = Executors.newSingleThreadExecutor();
        }
    }

    private static class SingleTonHolder {
        private static SerialPortUtils INSTANCE = new SerialPortUtils();
    }

    public static SerialPortUtils getInstance() {
        return SingleTonHolder.INSTANCE;
    }

    public boolean initSerialPort(String path, int baudrate,Handler handler) {
        try {
            if (mSerialPort == null) mSerialPort =getSerialPort(path, baudrate);
            if (serialPortOutputStream == null) {
                serialPortOutputStream = mSerialPort.getOutputStream();
            }
            if (serialPortInputStream == null) {
                serialPortInputStream = mSerialPort.getInputStream();
            }
//            Log.e(TAG, "mSerialPort: " + mSerialPort);
//            Log.e(TAG, "serialPortOutputStream: " + serialPortOutputStream);
//            Log.e(TAG, "serialPortInputStream: " + serialPortInputStream);
            if (mSerialPort == null || serialPortOutputStream == null
                    || serialPortInputStream == null) {
                handler.obtainMessage(Flags.SHOW_TOAST, "fail").sendToTarget();
                return false;
            }
        } catch (SecurityException e) {
            e.printStackTrace();
            handler.obtainMessage(Flags.SHOW_TOAST, "fail").sendToTarget();
            return false;
        } catch (InvalidParameterException e) {
            e.printStackTrace();
            handler.obtainMessage(Flags.SHOW_TOAST, "fail").sendToTarget();
            return false;
        }
        handler.obtainMessage(Flags.SHOW_TOAST, "successful").sendToTarget();
        handler.obtainMessage(Flags.SERIAL_PORT_SUCCESS).sendToTarget();
        return true;
    }

    /**
     * 通过串口将数据返回给PC端  设备发送数据给PC
     */
    public void onSerialPortDataWrite(String res, Handler handler) {
        singleThreadExecutor.execute(() -> {
            try {
                if ("7f".equals(res)) {
//                    Log.e(TAG, "onSerialPortDataWrite hexStr: " + res);
                    if (serialPortOutputStream == null) {
//                        handler.obtainMessage(Flags.SHOW_TOAST, MyApplication.Companion.getContext().getString(R.string.failed_serialport)).sendToTarget();
                        handler.obtainMessage(Flags.SHOW_TOAST,"fail").sendToTarget();
                    }
                    byte[] buffer = GPMethods.str2bytes(res);
                    serialPortOutputStream.write(buffer);
                    serialPortOutputStream.flush();
//                    Log.e(TAG, "onSerialPortDataWrite buffer: " + GPMethods.bytesToHexString(buffer));
                } else {
                    String hexStr = GPMethods.str2HexStr(res);
                    byte[] buffer = GPMethods.str2bytes(hexStr);
                    int size = buffer.length;
//                    Log.e(TAG, "onSerialPortDataWrite res: " + res + " , hexStr : " + hexStr);
//                    Log.e(TAG, "write data len: " + size);
//                    Log.e(TAG, "onSerialPortDataWrite serialPortOutputStream: " + serialPortOutputStream);
                    if (serialPortOutputStream == null) {
                        handler.obtainMessage(Flags.SHOW_TOAST, "fail").sendToTarget();
                        waitPortData = false;
                    }
                    serialPortOutputStream.write(buffer);
                    serialPortOutputStream.flush();
//                    Log.e(TAG, "onSerialPortDataWrite buffer: " + GPMethods.bytesToHexString(buffer));
                }
            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, "onSerialPortDataWrite Exception: " + e.getMessage());
            }
        });
    }

    /**
     * 从串口读取上位机发送过来的信息,   设备接收数据
     *
     * @return
     */
    public String readDataBySerialPort(Handler handler) {
        String str = "";
        try {
            if (serialPortInputStream == null) {
                Log.e(TAG, "serialPortInputStream is null");
            } else {
                byte[] bt = readStream(serialPortInputStream);
                if (bt != null) {
                    String hexStr = GPMethods.bytesToHexString(bt);
                    if (!hexStr.contains("7f")) {
                        str = GPMethods.hexStr2Str(hexStr);
                        Log.e(TAG, "readDataBySerialPort receive msg: " + str);
                        handler.obtainMessage(Flags.HSM_MANAGE_RECEIVE, str).sendToTarget();
                    } else {
                        StringBuilder temp = new StringBuilder();
                        for (int i = 0; i < hexStr.length(); i += 2) {
                            char char1 = hexStr.charAt(i);
                            char char2 = hexStr.charAt(i + 1);
                            if (char1 == '7' && char2 == 'f') {
                                String hexData = temp.toString();
                                if (!TextUtils.isEmpty(hexData)) {
                                    str = GPMethods.hexStr2Str(hexData);
                                    handler.obtainMessage(Flags.HSM_MANAGE_RECEIVE, str).sendToTarget();
                                }
                                temp = new StringBuilder();
                                handler.obtainMessage(Flags.HSM_DELETE_RECEIVE).sendToTarget();
                            } else {
                                temp.append(char1).append(char2);
                            }
                        }
                        String hexData = temp.toString();
                        if (!TextUtils.isEmpty(hexData)) {
                            str = GPMethods.hexStr2Str(hexData);
                            handler.obtainMessage(Flags.HSM_MANAGE_RECEIVE, str).sendToTarget();
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "readDataBySerialPort Exception: " + e.getMessage());
        }
        return str;
    }

    /**
     * @param inStream
     * @return 字节数组
     * @throws Exception
     * @功能 读取流
     */
    public byte[] readStream(InputStream inStream) throws IOException {
        byte[] data = null;
        byte[] buffer = new byte[3072];
        int len = 0;
        len = inStream.read(buffer);
        // Log.e(TAG, "readStream len: " + len);
        if (len > 0) {
//            Log.e(TAG, "readStream buffer:　" + GPMethods.bytesToHexString(buffer));
            data = new byte[len];
            System.arraycopy(buffer, 0, data, 0, len);
//            Log.e(TAG, "readStream buffer:　" + GPMethods.bytesToHexString(data));
        }
        return data;
    }

    /**
     * 关闭串口通信，释放资源
     */
    public void closePort() {
        try {
            closeSerialPort();
            mSerialPort = null;
            if (serialPortOutputStream != null) {
                serialPortOutputStream.close();
                serialPortOutputStream = null;
            }
            if (serialPortInputStream != null) {
                serialPortInputStream.close();
                serialPortInputStream = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private SerialPort getSerialPort(String path,int baudRate) {
        try {
            if (mSerialPort == null) {
                /* Check parameters */
                if (path.getBytes().length == 0 || baudRate == -1) {
                    throw new InvalidParameterException();
                }
                mSerialPort =new SerialPort(new File(path), baudRate, 0, 8, 1);
            }
        }catch (SerialPort.SerialPortException e){
            e.printStackTrace();
        }
        return mSerialPort;
    }
    private void closeSerialPort() {
        if (mSerialPort != null) {
            mSerialPort.close();
            mSerialPort = null;
        }
    }
}